from enum import Enum, IntEnum
import logging
from typing import Any, Optional
from fastapi import FastAPI, HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel

class CustomEnum(Enum):
    @classmethod
    def valid(cls, value):
        try:
            cls(value)
            return True
        except BaseException:
            return False

    @classmethod
    def values(cls):
        return [member.value for member in cls.__members__.values()]

    @classmethod
    def names(cls):
        return [member.name for member in cls.__members__.values()]

class RetCode(IntEnum, CustomEnum):
    SUCCESS = 0
    NOT_EFFECTIVE = 10
    EXCEPTION_ERROR = 100
    ARGUMENT_ERROR = 101
    DATA_ERROR = 102
    OPERATING_ERROR = 103
    CONNECTION_ERROR = 105
    RUNNING = 106
    PERMISSION_ERROR = 108
    AUTHENTICATION_ERROR = 109
    UNAUTHORIZED = 401
    SERVER_ERROR = 500
    FORBIDDEN = 403
    NOT_FOUND = 404

class BaseResponse(BaseModel):
    code: int
    message: str
    data: Optional[Any]
    
def get_json_result(*, code=RetCode.SUCCESS, message="success", data=None):
    response = {"code": code, "message": message, "data": data}
    return response

def server_error_response(e):
    logging.exception(e)
    try:
        if e.code == 401:
            return get_json_result(code=401, message=repr(e))
    except BaseException:
        return get_json_result(code=RetCode.EXCEPTION_ERROR,
                               message=f"Exception: {get_json_result(code=RetCode.EXCEPTION_ERROR, message=str(e))}")
    if len(e.args) > 1:
        return get_json_result(code=RetCode.EXCEPTION_ERROR, message=repr(e.args[0]), data=e.args[1])
    if repr(e).find("index_not_found_exception") >= 0:
        return get_json_result(code=RetCode.EXCEPTION_ERROR, message="No chunk found, please upload file and parse it.")

    return get_json_result(code=RetCode.EXCEPTION_ERROR, message=repr(e))

def register_exception_handler(app: FastAPI):
    @app.exception_handler(Exception)
    async def global_exception_handler(request: Request, exc: Exception):
        return JSONResponse(content=server_error_response(exc))
    
    @app.exception_handler(HTTPException)
    async def http_exception_handler(request: Request, exc: HTTPException):
        logging.warning(f"HTTPException: {str(exc)}")
        return JSONResponse(content=get_json_result(code=RetCode.EXCEPTION_ERROR,
                                                    message=f"HTTP error, detail={exc.detail}"))
    
    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
        logging.warning(f"RequestValidationError: {str(exc)}")
        return JSONResponse(content=get_json_result(code=RetCode.EXCEPTION_ERROR,
                                                    message=f"Validation error, content={str(exc)}"))